class AClockworkBanana
  
  attr_reader :errors, :model
  
  def initialize store, model
    raise AClockworkBananaException, 'Did not receive APersistentBanana' unless store.kind_of? APersistentBanana
    raise AClockworkBananaException, 'Did not receive AModelBanana' unless model.kind_of? AModelBanana
    @store = store
    @model = model
    @errors = []
  end
  
  # effectively turns each instance into the object for the given key
  # by loading each field and exposing it via accessors
  def turn key, writable=false, new=false
    @model.fields.each do |f|
      # TODO: error handling
      if new
        self.instance_variable_set "@#{f}", ''
      else
        var = @store.get_value key + "/" + f
        self.instance_variable_set "@#{f}", var
      end
      if writable
        AClockworkBanana.send :attr_accessor, f.to_sym
      else
        AClockworkBanana.send :attr_reader, f.to_sym
      end
    end
  end
  
  # report validity of the object
  def is_valid?
    validate
    @errors.length == 0
  end
  
  private
  
  def validate
    attr = []
    @errors = []
    self.instance_variables.each do |var|
      next if [:@model, :@store, :@errors].include? var
      attr.push var.to_s.slice(1, var.to_s.length)
    end
    (attr - @model.fields).each do |extra|
      @errors.push "Object contains the extra field #{extra}."
    end
    (@model.fields - attr).each do |missing|
      @errors.push "Object is missing the field #{missing}."
    end
    (attr & @model.fields).each do |matching|
      fieldtype = @model.fieldtypes[matching]
      constraint = @model.constraints.key?(matching) ? @model.constraints[matching] : nil
      @errors.push "Invalid value for #{matching}." unless AValidatoryBanana.validate(fieldtype, self.send(matching.to_sym), constraint)
    end
  end
  
end